<?php

namespace app\service;


use app\model\TaskModel;
use app\model\TaskWorkOrderModel;
use app\model\UserModel;
use app\tool\SingletonTrait;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;

class UserStatisticsService
{
    use SingletonTrait;

    /**
     * 角色下各用户任务状态统计
     * @param array $param
     * @return array
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public function userRoleTaskCount(array $param): array
    {
        $res = [];
        if (!in_array($param['role_code'], ['director'])) {
            return $res;
        }

        $userIdList = ProjectMemberService::getInstance()->getProjectRoleUserIdList($param['project_id'], $param['role_code']);
        if (empty($userIdList)) {
            return $res;
        }
        $userList = UserModel::field('id, name')
            ->whereIn('id', $userIdList)
            ->select()->toArray();

        $doneSql = 'get_json_string(task.`json`, "$.task_status") = ' . StatusService::getInstance()->byCode('final', 'id');
        $noSolutionSql = 'get_json_string(task.`json`, "$.task_status") not in (' . StatusService::getInstance()->byCodeMap(['closed', 'final'], false, 'id') . ')'
            . ' and two.id is null and (dot.id is null or dot.manager_confirmed <> "yes")';
        $hasSolutionSql = 'get_json_string(task.`json`, "$.task_status") not in (' . StatusService::getInstance()->byCodeMap(['closed', 'final'], false, 'id') . ')'
            . ' and (two.id is not null or (dot.id is not null and (dot.type = "today_done" or dot.manager_confirmed = "yes")))';

        $dotJoin = TaskStatisticsService::getWindowedLastDelayOrderTask($param['start_time'], $param['end_time'], ['original_plan_time', 'plan_delivery_time']);
        $taskCount = TaskModel::where('task.project_id', $param['project_id'])
            ->join(['task_member' => 'tm'], 'tm.task_id = task.id and tm.partner in (' . implode(',', $userIdList) . ')')
            ->join('user', 'user.id = tm.partner')
            ->join([$dotJoin => 'dot'], 'dot.task_id = task.id', 'left')
            ->join(['task_work_order' => 'two'], 'two.task_id = task.id and two.status in ( ' . TaskWorkOrderModel::STATUS_UNTREATED . ',' . TaskWorkOrderModel::STATUS_PROGRESS . ')', 'left')
            ->whereBetween('task.plan_end_time', [$param['start_time'], $param['end_time']])
            ->whereNotIn('task.step_type', ['step', 'step_category'])
            ->whereFieldRaw('get_json_string(task.`json`, "$.task_status")', '<>', StatusService::getInstance()->byCode('closed', 'id'))
            ->fieldRaw('user.id as user_id'
                . ', count(distinct task.id) as total'
                . ', count(distinct if(' . $doneSql . ', task.id, null)) as done'
                . ', count(distinct if(' . $noSolutionSql . ', task.id, null)) as no_solution'
                . ', count(distinct if(' . $hasSolutionSql . ', task.id, null)) as has_solution')
            ->group('user.id')
            ->select()->toArray();
        $userTaskMap = empty($taskCount) ? [] : array_combine(array_column($taskCount, 'user_id'), $taskCount);

        return array_map(fn($item) => [
            'id' => intval($item['id']),
            'name' => $item['name'],
            'total' => intval($userTaskMap[$item['id']]['total'] ?? 0),
            'done' => intval($userTaskMap[$item['id']]['done'] ?? 0),
            'no_solution' => intval($userTaskMap[$item['id']]['no_solution'] ?? 0),
            'has_solution' => intval($userTaskMap[$item['id']]['has_solution'] ?? 0),
        ], $userList);
    }
}

